package com.zzyl.device.service.impl;

import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.*;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpStatus;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.huaweicloud.sdk.iotda.v5.IoTDAClient;
import com.huaweicloud.sdk.iotda.v5.model.*;
import com.zzyl.common.constant.CacheConstants;
import com.zzyl.common.core.domain.AjaxResult;
import com.zzyl.common.core.domain.entity.SysUser;
import com.zzyl.common.core.page.TableDataInfo;
import com.zzyl.common.exception.base.BaseException;
import com.zzyl.device.domain.DeviceData;
import com.zzyl.device.domain.dto.DeviceDataPageReqDto;
import com.zzyl.device.service.IDeviceDataService;
import com.zzyl.device.domain.IotMsgNotifyData;
import com.zzyl.device.domain.IotMsgService;
import com.zzyl.framework.config.properties.HuaWeiIotConfigProperties;
import com.zzyl.nursing.dto.DeviceDto;
import com.zzyl.nursing.vo.DeviceDetailVo;
import com.zzyl.nursing.vo.ProductVo;
import com.zzyl.system.service.ISysUserService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import com.zzyl.device.mapper.DeviceMapper;
import com.zzyl.device.domain.Device;
import com.zzyl.device.service.IDeviceService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.transaction.annotation.Transactional;

import java.util.stream.Collectors;

/**
 * 设备管理Service业务层处理
 * 
 * @author ruoyi
 * @date 2025-10-23
 */
@Service
public class DeviceServiceImpl extends ServiceImpl<DeviceMapper, Device> implements IDeviceService
{
    @Autowired
    private DeviceMapper deviceMapper;

    @Autowired
    private IoTDAClient client;

    @Autowired
    private  RedisTemplate redisTemplate;

    @Autowired
    private HuaWeiIotConfigProperties configProperties;

    @Autowired
    private ISysUserService userService;

    @Autowired
    private IDeviceDataService deviceDataService;

    /**
     * 查询设备管理
     * 
     * @param id 设备管理主键
     * @return 设备管理
     */

    /**
     * 查询设备管理列表
     * 
     * @param device 设备管理
     * @return 设备管理
     */
    @Override
    public List<Device> selectDeviceList(Device device)
    {
        return deviceMapper.selectDeviceList(device);
    }



    @Override
    public List<ProductVo> allProduct() {
        String Str =(String) redisTemplate.opsForValue().get(CacheConstants.GET_PRODECT_LIST_KEY);

        if (StrUtil.isBlank(Str)){
            return Collections.EMPTY_LIST;
        }

        List<ProductSummary> list = JSONUtil.toList(Str, ProductSummary.class);
        List<ProductVo> res = list.stream().map(item -> {
            return ProductVo.builder()
                    .productKey(item.getProductId())
                    .productName(item.getName())
                    .build();
        }).collect(Collectors.toList());
        return res;
    }

    @Override
    public void syncProductList() {
        ListProductsResponse Response = client.listProducts(new ListProductsRequest());

        if (Response.getHttpStatusCode() != HttpStatus.HTTP_OK){
            throw new BaseException("同步产品列表失败！");
        }

        String jsonStr = JSONUtil.toJsonStr(Response.getProducts());
        redisTemplate.opsForValue().set(CacheConstants.GET_PRODECT_LIST_KEY,jsonStr);
    }

    @Transactional
    @Override
    public void register(DeviceDto dto) {
        Device d1 = this.lambdaQuery()
                .eq(Device::getDeviceName, dto.getDeviceName())
                .one();
        if (ObjectUtil.isNotEmpty(d1)){
            throw new BaseException("设备名称重复");
        }

        String  nodeId = IdUtil.getSnowflakeNextIdStr();

        Device d2 = this.lambdaQuery()
                .eq(Device::getLocationType, dto.getLocationType())
                .eq(Device::getBindingLocation, dto.getBindingLocation())
                .eq(Device::getProductKey, dto.getProductKey())
                .one();

        if (ObjectUtil.isNotEmpty(d2)){
            throw new BaseException("绑定了重复的设备");
        }

        AddDevice body = new AddDevice();
        body.setNodeId(nodeId);
        body.setDeviceName(dto.getDeviceName());
        body.setProductId(dto.getProductKey());
        AuthInfo authInfo = new AuthInfo();
        String secret = IdUtil.fastSimpleUUID();
        authInfo.setSecret(secret);
        body.setAuthInfo(authInfo);
        body.setDescription(dto.getDeviceDescription());
        AddDeviceRequest addDeviceRequest = new AddDeviceRequest();
        addDeviceRequest.setBody(body);
        AddDeviceResponse addDeviceResponse = client.addDevice(addDeviceRequest);

        if (addDeviceResponse.getHttpStatusCode() != HttpStatus.HTTP_CREATED){
            throw  new BaseException("注册失败");
        }

        Device in = BeanUtil.toBean(dto, Device.class);
        in.setIotId(addDeviceResponse.getDeviceId());

        in.setHaveEntranceGuard(in.getNickname().contains("门禁") ? 1:0);
        in.setSecret(secret);
        in.setProductName(addDeviceResponse.getProductName());
        in.setNodeId(nodeId);
        this.save(in);


    }

    @Override
    public DeviceDetailVo getDetail(String iotId, String productKey) {
        Device device = this.getOne(Wrappers.<Device>lambdaQuery()
                .eq(Device::getIotId, iotId)
                .eq(Device::getProductKey, productKey)
        );
        System.out.println(device);
        if (ObjectUtil.isEmpty(device)){
            throw new BaseException("表中设备不存在");
        }

        ShowDeviceRequest showDeviceRequest = new ShowDeviceRequest();
        showDeviceRequest.withDeviceId(device.getIotId());
        ShowDeviceResponse showDeviceResponse = client.showDevice(showDeviceRequest);

        if (showDeviceResponse.getHttpStatusCode() != HttpStatus.HTTP_OK){
            throw new BaseException("云端设备不存在");
        }

        DeviceDetailVo res = BeanUtil.toBean(device, DeviceDetailVo.class);
        res.setRegion(configProperties.getRegionId());
        res.setGmtCreate(device.getCreateTime());
        res.setDeviceSecret(device.getSecret());
        SysUser sysUser = userService.selectUserById(Long.valueOf(device.getCreateBy()));
        res.setCreator(sysUser.getUserName());
        res.setFirmwareVersion(showDeviceResponse.getFwVersion());
        res.setDeviceSecret(showDeviceResponse.getStatus());
        if (StrUtil.isNotBlank(showDeviceResponse.getActiveTime())){
            LocalDateTime gmtActive = OffsetDateTime.parse(showDeviceResponse.getActiveTime())
                    .atZoneSameInstant(ZoneId.of("Asia/Shanghai"))
                    .toLocalDateTime();
            res.setGmtActive(gmtActive);
        }

        return res;
    }

    @Override
    public JSONObject queryProductModelInfo(Device device) {
        if (StrUtil.isBlank(device.getProductKey())){
            throw new BaseException("请传入正确的参数！");
        }

        ShowProductRequest showProductRequest = new ShowProductRequest();
        showProductRequest.withProductId(device.getProductKey());

        ShowProductResponse resp = null;
        try {
            resp = client.showProduct(showProductRequest);
        } catch (Exception e) {
            throw new BaseException("云端产品不存在！");
        }

        JSONObject res = null;
        List<ServiceCapability> serviceCapabilities = resp.getServiceCapabilities();
        if (CollectionUtil.isNotEmpty(serviceCapabilities)){
             res = JSONUtil.parseObj(serviceCapabilities.get(0));
        }
        return res;
    }

    @Override
    public AjaxResult queryDevicePropertyStatus(String deviceName, String productKey) {
        Device device = this.lambdaQuery()
                .eq(Device::getDeviceName, deviceName)
                .eq(Device::getProductKey, productKey)
                .one();

        if (ObjectUtil.isEmpty(device)){
            throw  new BaseException("设备不存在！");
        }

        ShowDeviceShadowRequest showDeviceShadowRequest = new ShowDeviceShadowRequest();
        showDeviceShadowRequest.withDeviceId(device.getIotId());
        ShowDeviceShadowResponse resp = client.showDeviceShadow(showDeviceShadowRequest);

        if (resp.getHttpStatusCode() != HttpStatus.HTTP_OK){
            throw  new BaseException("查询云端物模型运行状态失败！");
        }
        List<DeviceShadowData> shadow = resp.getShadow();
        if (CollectionUtil.isEmpty(shadow)){
            return AjaxResult.success(Collections.EMPTY_LIST);
        }

        JSONObject entries = JSONUtil.parseObj(shadow.get(0).getReported().getProperties());

        LocalDateTime eventTime = OffsetDateTime.parse(shadow.get(0).getReported().getEventTime(), DateTimeFormatter.ofPattern("yyyyMMdd'T'HHmmssX"))
                .atZoneSameInstant(ZoneId.of("Asia/Shanghai"))
                .toLocalDateTime();

        List<Map<String,Object>>  list = new ArrayList<>();

        entries.forEach((k,v) -> {
            Map<String,Object> map = new HashMap<>();
            map.put("identifier",k);
            map.put("value",v);
            map.put("time",eventTime);
            list.add(map);
        });

        Map<String ,Object> propertyStatusInfo = new HashMap<>();
        propertyStatusInfo.put("propertyStatusInfo",list);

        Map<String ,Object> result = new HashMap<>();
        result.put("list",propertyStatusInfo);

        return AjaxResult.success(result);
    }

    @Override
    @Transactional
    public void updateDevice(DeviceDto dto) {
        Device device = this.lambdaQuery()
                .eq(Device::getId, dto.getId())
                .one();
        if (ObjectUtil.isEmpty(device)){
            throw new BaseException("设备不存在！");
        }

        String iotId = device.getIotId();
        BeanUtils.copyProperties(dto,device);
        this.updateById(device);

        UpdateDeviceRequest updateRes = new UpdateDeviceRequest();
        UpdateDevice body = new UpdateDevice();
        body.setDeviceName(dto.getDeviceName());
        updateRes.setBody(body);
        updateRes.withDeviceId(iotId);
        UpdateDeviceResponse resp = client.updateDevice(updateRes);
        if (resp.getHttpStatusCode() != HttpStatus.HTTP_OK){
            throw  new BaseException("修改云端数据失败！");
        }
    }

    @Override
    public void delete(String iotId, String productKey) {
        boolean remove = this.lambdaUpdate()
                .eq(Device::getIotId, iotId)
                .eq(Device::getProductKey, productKey)
                .remove();

        if (!remove){
            throw new BaseException("设备不存在或已被删除！");
        }

        DeleteDeviceRequest deleteres = new DeleteDeviceRequest();
        deleteres.setDeviceId(iotId);

        try {
            client.deleteDevice(deleteres);
        } catch (Exception e) {
            e.printStackTrace();
            throw new BaseException("删除设备失败！");
        }
    }

    @Override
    public void saveBatchInfo(IotMsgNotifyData notifyData) {
        Device device = this.lambdaQuery().eq(Device::getIotId, notifyData.getHeader().getDeviceId()).one();
        if (ObjectUtil.isEmpty(device)){
            throw new BaseException("设备不存在！");
        }

        List<IotMsgService> services = notifyData.getBody().getServices();
        System.out.println(services);
        List<DeviceData> deviceDataList = new ArrayList<>();

        services.forEach(x ->{
            String eventTime = x.getEventTime();
            System.out.println("eventTimegetBefore");
            LocalDateTime alartTime = OffsetDateTime.parse(eventTime, DateTimeFormatter.ofPattern("yyyyMMdd'T'HHmmssX"))
                    .atZoneSameInstant(ZoneId.of("Asia/Shanghai"))
                    .toLocalDateTime();
            System.out.println("eventTimegetAfter");
            Map<String, Object> propertiesList = x.getProperties();
            propertiesList.forEach((k,v) ->{
                DeviceData deviceData = BeanUtil.toBean(device, DeviceData.class);
                System.out.println(deviceData);
                deviceData.setId(null);
                deviceData.setFunctionId(k);
                deviceData.setDataValue(String.valueOf(v));
                deviceData.setAlarmTime(alartTime);
                deviceData.setAccessLocation(device.getBindingLocation());

                deviceDataList.add(deviceData);
            });
        });

        deviceDataService.saveBatch(deviceDataList);

        redisTemplate.opsForHash().put(CacheConstants.LAST_DEVICE_DATA_LIST,device.getIotId(),JSONUtil.toJsonStr(deviceDataList));


    }

    @Override
    public TableDataInfo pegeGetInfo(DeviceDataPageReqDto dto) {
        Page<DeviceData> page = deviceDataService.lambdaQuery()
                .eq(dto.getDeviceId() != null, DeviceData::getIotId, dto.getDeviceId())
                .eq(dto.getDeviceName() != null, DeviceData::getDeviceName, dto.getDeviceName())
                .eq(dto.getFunctionId() != null, DeviceData::getFunctionId, dto.getFunctionId())
                .between(dto.getStartTime() != null && dto.getEndTime() != null, DeviceData::getAlarmTime, dto.getStartTime(), dto.getEndTime())
                .orderByDesc(DeviceData::getAlarmTime)
                .page(Page.of(dto.getPageNum(), dto.getPageSize()));

        TableDataInfo<DeviceData> rs= new TableDataInfo<>();
        rs.setTotal(page.getTotal());
        rs.setRows(page.getRecords());
        rs.setCode(200);

        return rs;
    }

}
